#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
数据管理器
负责数据的获取、缓存和管理
"""

import asyncio
from typing import Dict, Any, Optional, List, Callable
from datetime import datetime, timedelta
import pandas as pd
from collections import deque

from config.config_manager import get_config
from utils.logger import get_logger
from utils.exceptions import DataError, DataUnavailableError
from core.api_manager import get_api_manager
from core.base_classes import BaseDataProvider


class DataManager(BaseDataProvider):
    """数据管理器"""

    def __init__(self, symbol: str):
        super().__init__(symbol)
        self.config = get_config()
        self.api_manager = None

        # 数据缓存
        self.quote_cache = {}
        self.kline_cache = {}
        self.tick_cache = {}

        # 缓存时间戳
        self.cache_timestamps = {}

        # 数据更新回调
        self.update_callbacks = []

        # 初始化标志
        self._initialized = False

    async def initialize(self, api_manager):
        """初始化数据管理器"""
        self.api_manager = api_manager
        self._initialized = True
        self.logger.info(f"数据管理器初始化完成: {self.symbol}")

    async def get_quote(self) -> Dict[str, Any]:
        """获取实时行情"""
        if not self._initialized:
            raise DataError("数据管理器未初始化")

        try:
            # 检查缓存
            if self._is_cache_valid('quote'):
                return self.quote_cache

            # 从API获取数据
            quote_data = await self.api_manager.get_quote(self.symbol)

            # 缓存数据
            self.quote_cache = quote_data
            self.cache_timestamps['quote'] = datetime.now()

            # 通知订阅者
            await self._notify_subscribers('quote', quote_data)

            return quote_data

        except Exception as e:
            self.logger.error(f"获取行情失败: {e}")
            raise DataError(f"获取行情失败: {e}")

    async def get_kline_data(self, period: int, length: int) -> Dict[str, Any]:
        """获取K线数据"""
        if not self._initialized:
            raise DataError("数据管理器未初始化")

        cache_key = f"kline_{period}_{length}"

        try:
            # 检查缓存
            if self._is_cache_valid(cache_key):
                return self.kline_cache[cache_key]

            # 从API获取数据
            kline_data = await self.api_manager.get_kline_data(self.symbol, period, length)

            # 缓存数据
            self.kline_cache[cache_key] = kline_data
            self.cache_timestamps[cache_key] = datetime.now()

            return kline_data

        except Exception as e:
            self.logger.error(f"获取K线数据失败: {e}")
            raise DataError(f"获取K线数据失败: {e}")

    async def get_tick_data(self, length: int) -> Dict[str, Any]:
        """获取Tick数据"""
        if not self._initialized:
            raise DataError("数据管理器未初始化")

        cache_key = f"tick_{length}"

        try:
            # 检查缓存
            if self._is_cache_valid(cache_key):
                return self.tick_cache[cache_key]

            # 从API获取数据
            tick_data = await self.api_manager.get_tick_data(self.symbol, length)

            # 缓存数据
            self.tick_cache[cache_key] = tick_data
            self.cache_timestamps[cache_key] = datetime.now()

            return tick_data

        except Exception as e:
            self.logger.error(f"获取Tick数据失败: {e}")
            raise DataError(f"获取Tick数据失败: {e}")

    async def get_latest_quote(self) -> Optional[Dict[str, Any]]:
        """获取最新行情（不使用缓存）"""
        if not self._initialized:
            return None

        try:
            return await self.api_manager.get_quote(self.symbol)
        except Exception as e:
            self.logger.error(f"获取最新行情失败: {e}")
            return None

    async def get_latest_kline(self, period: int = 60) -> Optional[Dict[str, Any]]:
        """获取最新K线"""
        if not self._initialized:
            return None

        try:
            kline_data = await self.get_kline_data(period, 1)
            if kline_data and 'data' in kline_data and len(kline_data['data']) > 0:
                return kline_data['data'].iloc[-1].to_dict()
            return None
        except Exception as e:
            self.logger.error(f"获取最新K线失败: {e}")
            return None

    def _is_cache_valid(self, cache_key: str) -> bool:
        """检查缓存是否有效"""
        if not self.config.data.cache_enabled:
            return False

        if cache_key not in self.cache_timestamps:
            return False

        cache_time = self.cache_timestamps[cache_key]
        time_diff = (datetime.now() - cache_time).total_seconds()

        return time_diff < self.config.data.cache_ttl

    async def invalidate_cache(self, cache_key: Optional[str] = None):
        """使缓存失效"""
        if cache_key:
            # 清除特定缓存
            if cache_key == 'quote':
                self.quote_cache.clear()
            elif cache_key.startswith('kline_'):
                if cache_key in self.kline_cache:
                    del self.kline_cache[cache_key]
            elif cache_key.startswith('tick_'):
                if cache_key in self.tick_cache:
                    del self.tick_cache[cache_key]

            if cache_key in self.cache_timestamps:
                del self.cache_timestamps[cache_key]
        else:
            # 清除所有缓存
            self.quote_cache.clear()
            self.kline_cache.clear()
            self.tick_cache.clear()
            self.cache_timestamps.clear()

        self.logger.info(f"缓存已清除: {cache_key or 'all'}")

    async def wait_for_quote_update(self) -> Dict[str, Any]:
        """等待行情更新"""
        if not self._initialized:
            raise DataError("数据管理器未初始化")

        while True:
            await self.api_manager.wait_update()

            if self.api_manager.is_changing(self.quote_cache if self.quote_cache else None):
                # 重新获取最新行情
                updated_quote = await self.get_quote()
                await self._notify_subscribers('quote_update', updated_quote)
                return updated_quote

    async def wait_for_kline_update(self, period: int = 60) -> Dict[str, Any]:
        """等待K线更新"""
        if not self._initialized:
            raise DataError("数据管理器未初始化")

        cache_key = f"kline_{period}_1"
        kline_data = await self.get_kline_data(period, 1)
        last_kline = kline_data['data'].iloc[-1] if kline_data and 'data' in kline_data else None

        while True:
            await self.api_manager.wait_update()

            if self.api_manager.is_changing(last_kline, 'datetime'):
                # K线更新，清除相关缓存
                await self.invalidate_cache(f"kline_{period}")

                # 重新获取数据
                updated_kline_data = await self.get_kline_data(period, 1)
                updated_kline = updated_kline_data['data'].iloc[-1]

                await self._notify_subscribers('kline_update', updated_kline.to_dict())
                return updated_kline.to_dict()

    async def subscribe_quote_updates(self, callback: Callable):
        """订阅行情更新"""
        self.subscribe(callback)
        self.logger.info("已订阅行情更新")

    async def subscribe_kline_updates(self, callback: Callable, period: int = 60):
        """订阅K线更新"""
        async def kline_callback(data_type, data):
            if data_type == 'kline_update':
                await callback(data)

        self.subscribe(kline_callback)
        self.logger.info(f"已订阅K线更新: {period}秒周期")

    async def start_data_stream(self):
        """启动数据流"""
        if not self._initialized:
            raise DataError("数据管理器未初始化")

        self.logger.info(f"启动数据流: {self.symbol}")

        try:
            while True:
                # 等待数据更新
                await self.api_manager.wait_update()

                # 检查行情更新
                if self.api_manager.is_changing(self.quote_cache if self.quote_cache else None):
                    updated_quote = await self.get_quote()
                    await self._notify_subscribers('quote_update', updated_quote)

                # 检查K线更新（使用配置中的周期）
                kline_data = await self.get_kline_data(self.config.data.kline_period, 1)
                if kline_data and 'data' in kline_data and len(kline_data['data']) > 0:
                    last_kline = kline_data['data'].iloc[-1]
                    if self.api_manager.is_changing(last_kline, 'datetime'):
                        await self.invalidate_cache(f"kline_{self.config.data.kline_period}")
                        updated_kline_data = await self.get_kline_data(self.config.data.kline_period, 1)
                        updated_kline = updated_kline_data['data'].iloc[-1]
                        await self._notify_subscribers('kline_update', updated_kline.to_dict())

        except Exception as e:
            self.logger.error(f"数据流异常: {e}")
            raise DataError(f"数据流异常: {e}")

    def get_cache_stats(self) -> Dict[str, Any]:
        """获取缓存统计信息"""
        return {
            'quote_cache_size': len(self.quote_cache),
            'kline_cache_size': len(self.kline_cache),
            'tick_cache_size': len(self.tick_cache),
            'total_cache_entries': len(self.quote_cache) + len(self.kline_cache) + len(self.tick_cache),
            'cache_timestamps': list(self.cache_timestamps.keys()),
            'subscriber_count': len(self._subscribers)
        }

    async def cleanup(self):
        """清理资源"""
        await self.invalidate_cache()  # 清除所有缓存
        self._subscribers.clear()
        self._initialized = False
        self.logger.info("数据管理器已清理")


class MarketDataManager:
    """市场数据管理器"""

    def __init__(self):
        self.config = get_config()
        self.logger = get_logger("MarketDataManager")
        self.data_managers = {}
        self.api_manager = None

    async def initialize(self, api_manager):
        """初始化市场数据管理器"""
        self.api_manager = api_manager
        self.logger.info("市场数据管理器初始化完成")

    async def get_data_manager(self, symbol: str) -> DataManager:
        """获取指定合约的数据管理器"""
        if symbol not in self.data_managers:
            data_manager = DataManager(symbol)
            await data_manager.initialize(self.api_manager)
            self.data_managers[symbol] = data_manager

        return self.data_managers[symbol]

    async def get_multiple_quotes(self, symbols: List[str]) -> Dict[str, Dict[str, Any]]:
        """批量获取多个合约的行情"""
        results = {}

        for symbol in symbols:
            try:
                data_manager = await self.get_data_manager(symbol)
                quote = await data_manager.get_quote()
                results[symbol] = quote
            except Exception as e:
                self.logger.error(f"获取 {symbol} 行情失败: {e}")
                results[symbol] = None

        return results

    async def get_market_overview(self) -> Dict[str, Any]:
        """获取市场概览"""
        # 这里可以实现获取主要合约的综合信息
        return {
            'total_symbols': len(self.data_managers),
            'active_symbols': [symbol for symbol, manager in self.data_managers.items()
                             if manager._initialized],
            'cache_stats': {symbol: manager.get_cache_stats()
                          for symbol, manager in self.data_managers.items()}
        }

    async def cleanup(self):
        """清理所有数据管理器"""
        for symbol, manager in self.data_managers.items():
            try:
                await manager.cleanup()
            except Exception as e:
                self.logger.error(f"清理 {symbol} 数据管理器失败: {e}")

        self.data_managers.clear()
        self.logger.info("市场数据管理器已清理")


# 全局市场数据管理器实例
_market_data_manager = None

def get_market_data_manager() -> MarketDataManager:
    """获取全局市场数据管理器实例"""
    global _market_data_manager
    if _market_data_manager is None:
        _market_data_manager = MarketDataManager()
    return _market_data_manager

async def init_market_data_manager(api_manager) -> MarketDataManager:
    """初始化市场数据管理器"""
    global _market_data_manager
    _market_data_manager = MarketDataManager()
    await _market_data_manager.initialize(api_manager)
    return _market_data_manager
